﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using ADV_Evaluator;
using ADV_Evaluator.Data;
using ADV_Evaluator.Command;


namespace ADV_Editor {

    /// <summary>
    /// コマンドを一覧にして表示するリストボックス。ListBoxのラッパー。
    /// </summary>
    /// <remarks>これ関係のプログラムが多すぎるのでMainFormから分離した。</remarks>
    partial class CommandList : UserControl {

        /// <summary>
        /// コマンドのコピー＆ペーストの為のクリップボード。
        /// </summary>
        /// <remarks>staticなので全コマンドリストで共通。これにより複数のリストボックス間でコピー＆ペーストとかが可能。</remarks>
        static public List<CommandListData> Clipboard { get { return clipboard; } }
        static private List<CommandListData> clipboard = new List<CommandListData>();
        /// <summary>
        /// 編集しているファイル名
        /// </summary>
        public string FileName { 
            get { return fileName; }
            set { fileName = value; }
        }
        private string fileName;


        /// <summary>
        /// コンストラクタ
        /// </summary>
        public CommandList() {
            InitializeComponent();
            fileName = string.Empty;
        }


        #region メソッド
        /// <summary>
        /// リストボックスの描画を一時停止する。
        /// リストボックスの要素を大量にいじるときは事前に呼んでおく。
        /// </summary>
        public void BeginUpdate() {
            listBox.BeginUpdate();
        }
        /// <summary>
        /// リストボックスの描画を再開する。
        /// </summary>
        public void EndUpdate() {
            listBox.EndUpdate();
        }
        #endregion


        #region 外部へのイベントハンドラの公開
        /// <summary>
        /// 何かコマンドに変更が加えられると呼ばれるイベントハンドラ
        /// </summary>
        public ModifiedDelegate Modified;
        public delegate void ModifiedDelegate(string filename);
        /// <summary>
        /// リストボックスのインデックスが変化したら呼ばれるイベントハンドラ
        /// </summary>
        public SelectedIndexChangedDelegate SelectedIndexChanged;
        public delegate void SelectedIndexChangedDelegate(int index);
        private void listBox_SelectedIndexChanged(object sender, EventArgs e) {
            // 登録されているデリゲートを呼び出す
            if (SelectedIndexChanged != null) {
                SelectedIndexChanged(listBox.SelectedIndex);
            }
        }
        /*
        /// <summary>
        /// キー押下
        /// </summary>
        public new KeyEventHandler KeyDown;
        void listBox_KeyDown(object sender, KeyEventArgs e) {
            KeyDown(sender, e);
        }
        /// <summary>
        /// ダブルクリック
        /// </summary>
        public new MouseEventHandler MouseDoubleClick;
        void listBox_MouseDoubleClick(object sender, MouseEventArgs e) {
            MouseDoubleClick(sender, e);
        }
        /// <summary>
        /// マウスボタン押下
        /// </summary>
        public new MouseEventHandler MouseDown;
        void listBox_MouseDown(object sender, MouseEventArgs e) {
            MouseDown(sender, e);
        }
         * */
        #endregion


        #region 要素へのアクセス
        /// <summary>
        /// 選択している要素のインデックス
        /// </summary>
        public int SelectedIndex {
            get { return listBox.SelectedIndex; }
            set { listBox.SelectedIndex = value; }
        }
        /// <summary>
        /// 選択している要素。
        /// 選択されていなければnullとなるNullableを返す。
        /// </summary>
        public CommandListData? SelectedItem {
            get {
                if (listBox.SelectedIndex >= 0) {
                    return (CommandListData)listBox.SelectedItem;
                } else {
                    return null;
                }
            }
        }
        /// <summary>
        /// すべての要素
        /// </summary>
        public ListBox.ObjectCollection Items{
            get { return listBox.Items; }
        }
        /// <summary>
        /// インデクサ
        /// </summary>
        /// <param name="index">インデックス</param>
        /// <returns>要素</returns>
        public CommandListData this[int index] {
            get {
                return (CommandListData)listBox.Items[index];
            }
            set {
                listBox.Items[index] = value;
            }
        }
        #endregion


        #region コマンドの挿入
        /// <summary>
        /// 現在選択中のインデックスにコマンドを挿入
        /// </summary>
        /// <param name="command">挿入するコマンドデータ</param>
        /// <param name="singleLine">条件分岐等の複数行にかかわるコマンドを指定しても先頭の開始行だけを挿入したいときはtrue。つまり挿入で使うならtrueで編集ならfalseで。</param>
        /// <param name="updateIndent">挿入後インデントを調整するときtrue。ループの中でこの関数をつかうときはfalseにしておいて最後にUpdateIndentをすべし。</param>
        public void InsertCommand(CommandListData command, bool singleLine, bool updateIndent) {
            listBox.BeginUpdate();
            // リストボックスへ挿入
            listBox.Items.Insert(listBox.SelectedIndex, command);
            // 表示する値が複数行の場合、2行目以降もそれぞれListBoxへ挿入する
            if (command.IsMultiline) {
                for (int i = 0; i < command.RestLines.Length; i++) {
                    CommandListData child = new CommandListData(command.Name, command.RestLines[i]);
                    listBox.Items.Insert(listBox.SelectedIndex, child);
                }
            }

            // 条件分岐やループのときは終了行も追加する
            if (!singleLine) {
                switch (command.Name) {
                case CommandName.条件分岐: 
                    {
                        // 分岐の中の空行を挿入
                        listBox.Items.Insert(listBox.SelectedIndex, new CommandListData(CommandName.無し, new NullParams()));
                        // else節があれば追加
                        BranchParams param = (BranchParams)command.Data.Params;
                        if (param.HasElse) {
                            listBox.Items.Insert(listBox.SelectedIndex, new CommandListData(CommandName.それ以外の場合, new NullParams()));
                            listBox.Items.Insert(listBox.SelectedIndex, new CommandListData(CommandName.無し, new NullParams()));
                        }
                        // 分岐終了の行を追加
                        listBox.Items.Insert(listBox.SelectedIndex, new CommandListData(CommandName.分岐終了, new NullParams()));
                    }
                    break;
                case CommandName.ループ: 
                    {
                        // ループの中の空行とループ終了の行を挿入
                        listBox.Items.Insert(listBox.SelectedIndex, new CommandListData(CommandName.無し, new NullParams()));
                        listBox.Items.Insert(listBox.SelectedIndex, new CommandListData(CommandName.以上繰り返し, new NullParams()));
                    }
                    break;
                case CommandName.選択肢の表示: 
                    {
                        ChoiceParams param = (ChoiceParams)command.Data.Params;
                        // 各選択肢を追加
                        for (int i = 0; i < param.Options.Length; i++) {
                            ChoiceOptionParams option = new ChoiceOptionParams();
                            option.Text = param.Options[i];
                            listBox.Items.Insert(listBox.SelectedIndex, new CommandListData(CommandName.選択肢, option));
                            listBox.Items.Insert(listBox.SelectedIndex, new CommandListData(CommandName.無し, new NullParams()));                            
                        }
                        // 分岐終了の行を追加
                        listBox.Items.Insert(listBox.SelectedIndex, new CommandListData(CommandName.分岐終了, new NullParams()));                      
                    }
                    break;
                }
            }

            listBox.EndUpdate();
            // 変更済みフラグを立てる
            Modified(fileName);
            // インデントを再設定
            if (updateIndent) {
                UpdateIndent();
            }

        }
        /// <summary>
        /// インデントを再設定
        /// </summary>
        public void UpdateIndent() {

            // リストに格納されているのは構造体なので、一度変数にとってそれにアクセスしても値は変わらない。
            // 該当のインデックスの要素を直接いじるか再代入して書き換えよう。

            // 最初と最後の行のインデントは絶対０
            CommandListData first = (CommandListData)listBox.Items[0];
            CommandListData last = (CommandListData)listBox.Items[listBox.Items.Count - 1];
            first.Indent = last.Indent = 0;
            listBox.Items[0] = first;
            listBox.Items[listBox.Items.Count - 1] = last;

            byte indent = 0;
            // その他全体に繰り返し
            for (int i = 1; i < listBox.Items.Count - 1; i++) {
                CommandListData command = (CommandListData)listBox.Items[i];
                CommandListData upperCommand = (CommandListData)listBox.Items[i - 1];
                // 上が条件分岐開始行なら、その下から１つインデントをつける
                if (upperCommand.Name == CommandName.条件分岐 || 
                    upperCommand.Name == CommandName.それ以外の場合 || 
                    upperCommand.Name == CommandName.ループ ||
                    upperCommand.Name == CommandName.選択肢) 
                {
                    indent++;                
                }
                // 分岐終了はインデントを戻す
                else if (command.Name == CommandName.それ以外の場合 || 
                    command.Name == CommandName.分岐終了 || 
                    command.Name == CommandName.以上繰り返し) 
                {
                    indent--;
                }
                // 各選択肢は、選択開始行とインデントを同じに
                else if (command.Name == CommandName.選択肢) {
                    // 一番目の選択肢はインデントがついていないので除外。2番目以降だけ適用。
                    if (upperCommand.Name != CommandName.選択肢の表示) {
                        indent--;
                    }
                }

                // 現在の値と異なるときだけ、新しい値に変更する
                if (command.Indent != indent) {
                    command.Indent = indent;
                    listBox.Items[i] = command;
                }
            }
        }
        #endregion


        #region コマンドの削除・編集
        /// <summary>
        /// コマンドリストの選択中の項目のコピー
        /// </summary>
        public void CopyCommand() {
            // 選択中のデータ
            CommandListData? command = SelectedItem;
            // nullや空行なら不可
            if (!command.HasValue) {
                return;
            }
            CommandListData c = command.Value;
            if (c.Name == CommandName.無し) {
                return;
            }
            // クリップボードを初期化
            clipboard.Clear();
            // 選択中の行のデータを保存
            clipboard.Add(c);
            // 条件分岐なら分岐中のコマンド全てをコピー
            if (c.Name == CommandName.条件分岐 || c.Name == CommandName.ループ || c.Name == CommandName.選択肢の表示) {
                byte indent = c.Indent;
                // コピーする部分の末端の目印
                CommandName target;
                if (c.Name == CommandName.条件分岐 || c.Name == CommandName.選択肢の表示) {
                    target = CommandName.分岐終了;
                } else {
                    target = CommandName.以上繰り返し;
                }
                // インデントが同じ 分岐終了 が来るまで繰り返し
                for (int i = listBox.SelectedIndex + 1; i < listBox.Items.Count; i++) {
                    CommandListData _c = (CommandListData)listBox.Items[i];
                    clipboard.Add(_c);
                    if (_c.Name == target && indent == _c.Indent) {
                        break;
                    }
                }
            }
            // 複数行ならそれらの行を全てコピー
            else if (c.IsMultiline) {
                int i = listBox.SelectedIndex + 1;
                while (true) {
                    CommandListData _c = (CommandListData)listBox.Items[i];
                    if (!_c.IsSelectable) {
                        clipboard.Add(_c);
                    } else {
                        break;
                    }
                    i++;
                }
            }
        }
        /// <summary>
        /// コマンドリストの選択中の項目の削除
        /// </summary>
        public void DeleteCommand() {
            int index = listBox.SelectedIndex;
            CommandListData? command = SelectedItem;
            // 選択項目が無ければ不可
            if (!command.HasValue) {
                return;
            }
            // 空行等は消せない
            CommandListData c = command.Value;
            if (c.Name == CommandName.無し ||
                c.Name == CommandName.それ以外の場合 ||
                c.Name == CommandName.分岐終了 ||
                c.Name == CommandName.以上繰り返し ||
                c.Name == CommandName.選択肢) 
            {
                return;
            }
            // 条件分岐、ループなら中のコマンド全てを削除
            if (c.Name == CommandName.条件分岐 || c.Name == CommandName.ループ || c.Name == CommandName.選択肢の表示) {
                byte indent = c.Indent;
                // 消す部分の末端の目印
                CommandName target;
                if (c.Name == CommandName.条件分岐 || c.Name == CommandName.選択肢の表示) {
                    target = CommandName.分岐終了;
                } else {
                    target = CommandName.以上繰り返し;
                }
                // 削除
                listBox.Items.RemoveAt(index);
                // インデントが同じ 分岐終了 が来るまで繰り返し
                while (listBox.Items.Count > 0) {
                    c = (CommandListData)listBox.Items[index];
                    if (c.Name == target && indent == c.Indent) {
                        listBox.Items.RemoveAt(index);
                        break;
                    }
                    listBox.Items.RemoveAt(index);
                }
            }
            // 複数行ならそれらの行を全て削除
            else if (c.IsMultiline) {
                listBox.Items.RemoveAt(index);
                while (index < listBox.Items.Count) {
                    c = (CommandListData)listBox.Items[index];
                    if (!c.IsSelectable) {
                        listBox.Items.RemoveAt(index);
                    } else {
                        break;
                    }
                }
            } else {
                listBox.Items.RemoveAt(index);
            }
            // 削除してもカーソルの位置は変えない
            listBox.SelectedIndex = index;
            // 変更済みフラグを立てる
            Modified(fileName);
        }
        /// <summary>
        /// コマンドリストにクリップボードから貼り付け
        /// </summary>
        public void PasteCommand() {
            // クリップボードにデータがあるときだけ
            if (clipboard.Count > 0) {
                listBox.BeginUpdate();
                int index = listBox.SelectedIndex;
                // クリップボードのデータを全てリストボックスに挿入
                for (int i = 0; i < clipboard.Count; i++) {
                    listBox.Items.Insert(listBox.SelectedIndex, clipboard[i]);
                }
                // インデントを再設定
                UpdateIndent();
                // 変更済みフラグを立てる
                Modified(fileName);
                // 選択項目を復元
                listBox.SelectedIndex = index;
                listBox.EndUpdate();
            }
        }
        /// <summary>
        /// コマンドの編集
        /// </summary>
        public void EditCommand() {
            if (listBox.SelectedIndex == -1) {
                return;
            }
            // 編集前のコマンドデータ
            CommandListData command = (CommandListData)listBox.SelectedItem;
            // 複数行の2行目以降等は除外
            if (!command.IsSelectable) {
                return;
            }
            ICommandParams param = command.Params;
            CommandDialog.CommandDialogBase dialog;
            // 選択中の項目により分岐し、ダイアログを設定
            switch (command.Name) {
            case CommandName.文章の表示:
                dialog = new CommandDialog.MessageDialog((MessageParams)param); break;
            case CommandName.文章オプションの変更:
                dialog = new CommandDialog.MessageOptionDialog((MessageOptionParams)param); break;
            case CommandName.選択肢の表示:
                dialog = new CommandDialog.ChoiceDialog((ChoiceParams)param); break;
            case CommandName.注釈:
                dialog = new CommandDialog.NoteDialog((NoteParams)param); break;
            case CommandName.変数の操作:
                dialog = new CommandDialog.VariableDialog((VariableParams)param); break;
            case CommandName.条件分岐:
                dialog = new CommandDialog.BranchDialog((BranchParams)param); break;
            case CommandName.ループ:
                dialog = new CommandDialog.LoopDialog((LoopParams)param); break;
            case CommandName.ラベルの定義:
                dialog = new CommandDialog.LabelDialog(CommandName.ラベルの定義, (LabelParams)param); break;
            case CommandName.ラベルに飛ぶ:
                dialog = new CommandDialog.LabelDialog(CommandName.ラベルに飛ぶ, (LabelParams)param); break;
            case CommandName.シナリオの移動:
                dialog = new CommandDialog.ScenarioDialog(CommandName.シナリオの移動, (ScenarioParams)param); break;
            case CommandName.シナリオを埋め込む:
                dialog = new CommandDialog.ScenarioDialog(CommandName.シナリオを埋め込む, (ScenarioParams)param); break;
			case CommandName.クリッカブル領域の配置:
				dialog = new CommandDialog.ClickableMapDialog((ClickableMapParams)param); break;
			case CommandName.クリッカブル領域の削除:
				dialog = new CommandDialog.DeleteClickableMapDialog((DeleteClickableMapParams)param); break;
			case CommandName.立ち絵の表示:
            case CommandName.立ち絵の消去:
                dialog = new CommandDialog.ImageDialog((ImageParams)param); break;
            case CommandName.背景画像の表示:
            case CommandName.背景画像の消去:
                dialog = new CommandDialog.BgImageDialog((BgImageParams)param); break;
            case CommandName.背景色の変更:
                dialog = new CommandDialog.BackColorDialog((BackColorParams)param); break;
            case CommandName.トランジション準備:
                return;
            case CommandName.トランジション実行:
                dialog = new CommandDialog.TransitionDialog((TransitionParams)param); break;
            case CommandName.ＢＧＭの演奏:
            case CommandName.ＢＧＭの停止:
                dialog = new CommandDialog.BgmDialog((BgmParams)param); break;
            case CommandName.ＳＥの演奏:
            case CommandName.ＳＥの停止:
                dialog = new CommandDialog.SeDialog((SeParams)param); break;
            case CommandName.ウェイト:
                dialog = new CommandDialog.WaitDialog((WaitParams)param); break;
            default:
                return;
            }
            // OKが押されなかったらさようなら
            if (dialog.ShowDialog() != DialogResult.OK) {
                return;
            }

            // 現在のインデックスを保存しておく
            int index = listBox.SelectedIndex;
            // 再描画をロック
            listBox.BeginUpdate();

            // 条件分岐とループは複数行にわたるので特別に
            switch(dialog.Command.Name){
            case  CommandName.条件分岐:
                // else節有りと指定されたとき
                if (((BranchParams)dialog.Command.Params).HasElse) {
                    // まだelse節が無かったときは新設
                    if (!((BranchParams)param).HasElse) {
                        // まずは 分岐終了 があるところまでカウンタを回す
                        int i = index + 1;
                        byte indent = command.Indent;
                        while (i < listBox.Items.Count) {
                            CommandListData c = (CommandListData)listBox.Items[i];
                            if (c.Name == CommandName.分岐終了 && c.Indent == indent) {
                                break;
                            }
                            i++;
                        }
                        // その手前に、それ以外の場合 と空行を挿入
                        listBox.Items.Insert(i, new CommandListData(CommandName.無し, string.Empty));
                        listBox.Items.Insert(i, new CommandListData(CommandName.それ以外の場合, string.Empty));
                    }

                // else節無しの指定のとき
                } else {
                    // すでにelse節があるときは消す
                    if (((BranchParams)param).HasElse) {
                        // まずは それ以外の場合 があるところまでカウンタを回す
                        int i = index + 1;
                        byte indent = command.Indent;
                        while (i < listBox.Items.Count) {
                            CommandListData c = (CommandListData)listBox.Items[i];
                            if (c.Name == CommandName.それ以外の場合 && c.Indent == indent) {
                                break;
                            }
                            i++;
                        }
                        // そこから、分岐終了 の手前までを削除
                        while (i < listBox.Items.Count) {
                            CommandListData c = (CommandListData)listBox.Items[i];
                            if (c.Name == CommandName.分岐終了 && c.Indent == indent) {
                                break;
                            }
                            listBox.Items.RemoveAt(i);
                        }
                    }
                }
                // 分岐の中身まで一旦削除すると大変なので、先頭部分だけをいじる
                listBox.Items.RemoveAt(index);
                listBox.SelectedIndex = index;
                InsertCommand(dialog.Command, true, true);
                break;

            case CommandName.ループ:
                // 分岐の中身まで一旦削除すると大変なので、先頭部分だけをいじる
                listBox.Items.RemoveAt(index);
                listBox.SelectedIndex = index;
                InsertCommand(dialog.Command, true, true);
                break;

            case CommandName.選択肢の表示: 
                {
                    ChoiceParams cp = (ChoiceParams)dialog.Command.Params;
                    // 今の各選択肢の子ノードを保存する
                    List<List<CommandListData>> options = new List<List<CommandListData>>();
                    for (int i = index + 1; i < listBox.Items.Count; i++) {
                        CommandListData c = (CommandListData)listBox.Items[i];
                        switch (c.Name) {
                        case CommandName.無し:
                            break;
                        case CommandName.分岐終了:
                            if (c.Indent == command.Indent) {
                                goto for_end;
                            }
                            break;
                        case CommandName.選択肢:
                            if (c.Indent == command.Indent) {
                                options.Add(new List<CommandListData>());
                            }
                            break;
                        default:
                            options[options.Count - 1].Add(c);
                            break;
                        }
                    }
                for_end:
                    // ノードを作り直す。各選択肢の子ノードは空になる。
                    DeleteCommand();
                    InsertCommand(dialog.Command, false, false);
                    // 各選択肢の子ノードに保存しておいた子ノードを割り当てる
                    for (int i = 0, j = index + 1; i < cp.Options.Length && i < options.Count; i++) {
                        for (; j < listBox.Items.Count; j++) {
                            CommandListData c = (CommandListData)listBox.Items[j];
                            if (c.Name == CommandName.選択肢 && c.Indent == dialog.Command.Indent) {
                                break;
                            }
                        }
                        j++;
                        for (int k = 0; k < options[i].Count; k++) {
                            listBox.Items.Insert(j, options[i][k]);
                            j++;
                        }
                    }
                    // インデントを再設定
                    UpdateIndent();
                }
                break;

            // 条件分岐以外の普通のコマンド
            default:
                // 削除してから挿入
                DeleteCommand();
                InsertCommand(dialog.Command, true, true);
                break;
            }

            // インデックスを保つ
            listBox.EndUpdate();
            listBox.SelectedIndex = index;
        }
        #endregion


        #region ListBoxのイベント

        /// <summary>
        /// コマンドリストの項目ごとの描画
        /// </summary>
        private void listBox_DrawItem(object sender, DrawItemEventArgs e) {
            if (e.Index == -1) {
                return;
            }
            // これから描画する項目
            CommandListData data = this[e.Index];
            // 文章の表示等の複数行にわたるコマンドの、2行目以降で無い場合、カーソルとして背景を青く描画
            if (data.IsSelectable) {
                e.DrawBackground();
            } else {
                e.Graphics.FillRectangle(Brushes.White, e.Bounds);
            }
            // 選択中の項目ならシステムカラー、そうでなければdataのブラシを使う
            Brush brush;
            if ((e.State & DrawItemState.Selected) == DrawItemState.Selected && data.IsSelectable) {
                brush = SystemBrushes.HighlightText;
            } else {
                brush = data.Brush;
            }
            // テキストの描画
            e.Graphics.DrawString(data.ToString(), e.Font, brush, e.Bounds);
            // カーソルの点線を描画
            e.DrawFocusRectangle();
        }
        /// <summary>
        /// コマンドリスト上でマウスがクリックされたときの処理。右クリックでの選択に対応させる
        /// </summary>
        private void listBox_MouseDown(object sender, MouseEventArgs e) {
            ListBox listBox = sender as ListBox;
            switch (e.Button) {
            // クリック
            case MouseButtons.Left:
            case MouseButtons.Right:
            case MouseButtons.Middle:
                // マウスポインタの指す項目のインデックスを取得し選択させる
                listBox.SelectedIndex = listBox.IndexFromPoint(e.Location);
                listBox.Focus();
                // 取得できなかったときは最後の項目を選択したことにする
                if (listBox.SelectedIndex == -1) {
                    listBox.SelectedIndex = listBox.Items.Count - 1;
                }
                // 選択中のコマンド
                CommandListData? command = SelectedItem;
                // コマンドが取得できたとき
                if (command.HasValue) {
                    // 右クリックメニューの状態を変化させる
                    // クリップボードが有るときだけ貼り付け可能
                    bool can_paste = (clipboard.Count > 0);
                    context_PasteCommand.Enabled = can_paste;
                    // 空行、条件分岐やループの終端などでないときだけ編集・コピー・切り取り・削除可能
                    bool can_edit = (command.Value.IsSelectable && command.Value.Name != CommandName.無し);
                    context_Edit.Enabled = can_edit;
                    context_CopyCommand.Enabled = can_edit;
                    context_CutCommand.Enabled = can_edit;
                    context_DeleteCommand.Enabled = can_edit;
                }
                break;
            }
        }
        /// <summary>
        /// コマンドリスト上でマウスがダブルクリックされたとき
        /// </summary>
        void listBox_MouseDoubleClick(object sender, MouseEventArgs e) {
            // 選択されたところの編集を開始
            EditCommand();
        }
        #endregion


        #region ContextMenuStripのイベント
        /// <summary>
        /// 右クリックメニューから「編集」がクリックされたとき
        /// </summary>
        private void context_EditCommnad_Click(object sender, EventArgs e) {
            EditCommand();
        }
        /// <summary>
        /// 右クリックメニューの削除を押したとき
        /// </summary>
        private void context_DeleteCommand_Click(object sender, EventArgs e) {
            DeleteCommand();
        }
        /// <summary>
        /// 右クリックメニューの切り取りを押したとき
        /// </summary>
        private void context_CutCommand_Click(object sender, EventArgs e) {
            // まずコピー、そのあと削除
            CopyCommand();
            DeleteCommand();
        }
        /// <summary>
        /// 右クリックメニューの貼り付けを押したとき
        /// </summary>
        private void context_PasteCommand_Click(object sender, EventArgs e) {
            PasteCommand();
        }
        /// <summary>
        /// 右クリックメニューのコピーを押したとき
        /// </summary>
        private void context_CopyCommand_Click(object sender, EventArgs e) {
            CopyCommand();
        }
        /// <summary>
        /// 右クリックメニューが開くとき
        /// </summary>
        private void contextMenu_Command_Opening(object sender, CancelEventArgs e) {
            // 開くコンテキストメニュー
            ContextMenuStrip cms = sender as ContextMenuStrip;
            // 現在選択しているコマンドを取得
            CommandListData? command = SelectedItem;
            // 選択している行が、文章の表示などの2行目以降の場合は、メニューは無効
            if (command.HasValue) {
                if (!command.Value.IsSelectable) {
                    if (command.Value.Name != CommandName.無し) {
                        cms.Enabled = false;
                        return;
                    }
                }
            }
            cms.Enabled = true;
        }
        /// <summary>
        /// 指定したコマンド名に応じたコマンドを挿入するためのダイアログを開く。
        /// もしダイアログを開く必要の無いコマンドならば即挿入する。
        /// </summary>
        /// <param name="name">コマンド名</param>
        public void ShowCommandDialog(CommandName name) {
            CommandDialog.CommandDialogBase dialog = null;
            switch (name) {
            case CommandName.文章の表示:
                dialog = new CommandDialog.MessageDialog(); break;
            case CommandName.文章オプションの変更:
                dialog = new CommandDialog.MessageOptionDialog(); break;
            case CommandName.選択肢の表示:
                dialog = new CommandDialog.ChoiceDialog(); break;
            case CommandName.変数の操作:
                dialog = new CommandDialog.VariableDialog(); break;
            case CommandName.条件分岐:
                dialog = new CommandDialog.BranchDialog(); break;
            case CommandName.ループ:
                dialog = new CommandDialog.LoopDialog(); break;
            case CommandName.ループを抜ける:
                InsertCommand(new CommandListData(CommandName.ループを抜ける, new NullParams()), true, true); break;
            case CommandName.ラベルの定義:
                dialog = new CommandDialog.LabelDialog(CommandName.ラベルの定義); break;
            case CommandName.ラベルに飛ぶ:
                dialog = new CommandDialog.LabelDialog(CommandName.ラベルに飛ぶ); break;
            case CommandName.シナリオの移動:
                dialog = new CommandDialog.ScenarioDialog(CommandName.シナリオの移動); break;
            case CommandName.シナリオを埋め込む:
                dialog = new CommandDialog.ScenarioDialog(CommandName.シナリオを埋め込む); break;
			case CommandName.クリッカブル領域の配置:
				dialog = new CommandDialog.ClickableMapDialog(); break;
			case CommandName.クリッカブル領域の削除:
				dialog = new CommandDialog.DeleteClickableMapDialog(); break;
			case CommandName.立ち絵の表示:
                dialog = new CommandDialog.ImageDialog(); break;
            case CommandName.背景画像の表示:
                dialog = new CommandDialog.BgImageDialog(); break;
			case CommandName.背景色の変更:
				dialog = new CommandDialog.BackColorDialog(); break;
			case CommandName.トランジション準備:
                InsertCommand(new CommandListData(CommandName.トランジション準備, new NullParams()), true, true); break;
            case CommandName.トランジション実行:
                dialog = new CommandDialog.TransitionDialog(); break;
            case CommandName.ＢＧＭの演奏:
                dialog = new CommandDialog.BgmDialog(); break;
            case CommandName.ＳＥの演奏:
                dialog = new CommandDialog.SeDialog(); break;
            case CommandName.注釈:
                dialog = new CommandDialog.NoteDialog(); break;
            case CommandName.ウェイト:
                dialog = new CommandDialog.WaitDialog(); break;
            }
            if (dialog != null && dialog.ShowDialog() == DialogResult.OK) {
                InsertCommand(dialog.Command, false, true);
            }
        }
        /// <summary>
        /// 文章の追加
        /// </summary>
        private void commandMenu_Message_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.文章の表示);
        }
        /// <summary>
        /// 文章オプションの変更
        /// </summary>
        private void commandMenu_MessageOption_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.文章オプションの変更);
        }
        /// <summary>
        /// 選択肢の表示
        /// </summary>
        private void commandMenu_Selection_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.選択肢の表示);
        }
        /// <summary>
        /// 変数の操作
        /// </summary>
        private void commandMenu_Variable_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.変数の操作);
        }
        /// <summary>
        /// 条件分岐
        /// </summary>
        private void commandMenu_Branch_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.条件分岐);
        }
        /// <summary>
        /// ループ
        /// </summary>
        private void commandMenu_Loop_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.ループ);
        }
        /// <summary>
        /// ループを抜ける
        /// </summary>
        private void commandMenu_LoopBreak_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.ループを抜ける);
        }
        /// <summary>
        /// ラベルの定義
        /// </summary>
        private void commandMenu_LabelDefine_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.ラベルの定義);
        }
        /// <summary>
        /// ラベルに飛ぶ
        /// </summary>
        private void commandMenu_LabelJump_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.ラベルに飛ぶ);
        }
        /// <summary>
        /// シナリオの移動
        /// </summary>
        private void commandMenu_JumpScenario_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.シナリオの移動);
        }
        /// <summary>
        /// シナリオを埋め込む
        /// </summary>
        private void commandMenu_IncludeScenario_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.シナリオを埋め込む);
        }
        /// <summary>
        /// 立ち絵の表示
        /// </summary>
        private void commandMenu_Image_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.立ち絵の表示);
        }
        /// <summary>
        /// 背景画像の表示
        /// </summary>
        private void commandMenu_BgImage_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.背景画像の表示);
        }
		/// <summary>
		/// 背景色の変更
		/// </summary>
		private void commandMenu_BackColor_Click(object sender, EventArgs e) {
			ShowCommandDialog(CommandName.背景色の変更);
		}
		/// <summary>
        /// トランジション準備
        /// </summary>
        private void commandMenu_TransitionPrepare_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.トランジション準備);
        }
        /// <summary>
        /// トランジション実行
        /// </summary>
        private void commandMenu_TransitionStart_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.トランジション実行);
        }
        /// <summary>
        /// BGMの演奏
        /// </summary>
        private void commandMenu_Bgm_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.ＢＧＭの演奏);
        }
        /// <summary>
        /// SEの演奏
        /// </summary>
        private void commandMenu_SE_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.ＳＥの演奏);
        }
        /// <summary>
        /// 注釈
        /// </summary>
        private void commandMenu_Note_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.注釈);
        }
        /// <summary>
        /// ウェイト
        /// </summary>
        private void commandMenu_Wait_Click(object sender, EventArgs e) {
            ShowCommandDialog(CommandName.ウェイト);
        }
        #endregion

    }

}
